<?php


namespace App\Controller\Frontend;


use App\Entity\Gallery;
use App\Entity\Menu;
use App\Entity\Page;
use App\Entity\PageCategory;
use App\Entity\PageTag;
use App\Entity\Setting;
use App\Entity\Subscribe;
use App\Service\Redis;
use App\Utils\Traits\JsonTrait;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends AbstractController {
    use JsonTrait;

    private $redis;
    private $limit = 10;

    public function __construct (Redis $client) {
        $this->redis = $client->redis;
    }

    /**
     * @Route("/", name="home_page")
     * @Template()
     * @return array
     */
    public function index () {
        return [];
    }

    /**
     * 菜单
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function menu () {
        $menus = $this->getDoctrine()->getRepository(Menu::class)->findBy([], ['position' => 'DESC']);
        return $this->render('frontend/public/header_menu.html.twig', [
            'menus' => $menus,
        ]);
    }

    /**
     * 首页幻灯
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function slide () {
        $pages = $this->getDoctrine()->getRepository(Page::class)->getRecommendPage();
        return $this->render('frontend/default/slide.html.twig', [
            'pages' => $pages,
        ]);
    }

    /**
     * 博文列表
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function page () {
        $top_page = $this->getDoctrine()->getRepository(Page::class)->getTopPage();
        $pages = $this->getDoctrine()->getRepository(Page::class)->getNewPage($this->limit);

        // 获取对应标签
        $page_tags = $this->getDoctrine()->getRepository(PageTag::class)->findAllToArray();
        foreach ($pages as &$page) {
            $items = [];
            $tag_ids = json_decode($page['page_tags'], true);
            foreach ($tag_ids as $tag_id) {
                if (isset($page_tags[$tag_id])) {
                    array_push($items, $page_tags[$tag_id]);
                }
            }
            $page['page_tags'] = $items;
        }

        return $this->render('frontend/default/page.html.twig', [
            'top_page' => $top_page,
            'pages' => $pages,
        ]);
    }

    /**
     * 获取更多文章
     * @param Request $request
     * @param EntityManagerInterface $em
     * @param PaginatorInterface $paginator
     * @Route("/default/page_load_more", name="default_page_load_more", methods={"POST"})
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
     */
    public function pageLoadMore (Request $request, EntityManagerInterface $em, PaginatorInterface $paginator) {
        if (!$request->isXmlHttpRequest()) {
            return $this->jsonFailure('请求错误');
        }

        $offset = $request->request->getInt('offset', 1) + 1;
        $dql = "SELECT p.id,p.title,p.thumbnail,p.publish_time,p.page_like,p.page_tags,p.summary,c.value as category,a.avatar,a.username,a.nickname
                    from App\Entity\Page as p 
                    left join App\Entity\PageCategory as c with p.page_category_id = c.id 
                    left join App\Entity\AdminUser as a with p.admin_user_id = a.id 
                    where p.status = 1 and p.is_top != 1 order by p.id DESC";

        $query = $em->createQuery($dql);
        $pagination = $paginator->paginate($query, $offset, $this->limit);

        // 获取对应标签
        $page_tags = $this->getDoctrine()->getRepository(PageTag::class)->findAllToArray();
        $pages = $pagination->getItems();
        foreach ($pages as &$page) {
            $items = [];
            foreach ($page['page_tags'] as $tag_id) {
                if (isset($page_tags[$tag_id])) {
                    array_push($items, $page_tags[$tag_id]);
                }
            }
            $page['page_tags'] = $items;
        }
        $pagination->setItems($pages);

        return $this->render('frontend/default/page_load_more.html.twig', [
            'pagination' => $pagination,
            'total'      => count($pagination->getItems()),
            'offset'     => $offset,
        ]);
    }

    /**
     * 热门博文
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function popularPost () {
        $pages = $this->getDoctrine()->getRepository(Page::class)->getHotPage(3);
        return $this->render('frontend/default/popular_post.html.twig', [
            'pages' => $pages,
        ]);
    }

    /**
     * 关于我
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function aboutMe () {
        $mine = $this->getDoctrine()->getRepository(Setting::class)->getCurrentSetting();
        return $this->render('frontend/default/about_me.html.twig', [
            'mine' => $mine,
        ]);
    }

    /**
     * 类别
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function category () {
        $category = $this->getDoctrine()->getRepository(PageCategory::class)->getTopCategory();

        // 排序
        $data = $category_data = $page_category = [];
        foreach ($category as $item) {
            $data[$item['id']] = $item['num'];
            $category_data[$item['id']] = $item;
        }
        arsort($data);
        foreach ($data as $id => $num) {
            array_push($page_category, $category_data[$id]);
        }

        return $this->render('frontend/default/category.html.twig', [
            'category' => array_slice($page_category, 0, 5),
        ]);
    }

    /**
     * 标签
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function tag () {
        $tags = $this->getDoctrine()->getRepository(PageTag::class)->findAll();
        return $this->render('frontend/default/tag.html.twig', [
            'tags' => $tags,
        ]);
    }

    /**
     * 订阅
     * @param Request $request
     * @Route("/common/subscribe", methods={"POST"}, name="common_subscribe")
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     * @throws \Exception
     */
    public function subscribe (Request $request) {
        if ($request->isXmlHttpRequest()) {
            $email = $request->request->get('email');
            $subscribe = $this->getDoctrine()->getRepository(Subscribe::class)->findOneBy(['email' => $email]);
            if (is_object($subscribe)) {
                return $this->jsonFailure('该邮箱已经订阅');
            }

            // 避免频繁订阅，同一个IP，一小时只允许订阅5次
            $ip = $request->getClientIp();
            $redis_key = $this->getParameter('app.name').':subscribe:'.$ip;
            if ($this->redis->exists($redis_key)) {
                $redis_value = $this->redis->get($redis_key);
                $redis_ttl = $this->redis->ttl($redis_key);
                if ($redis_value >= 5) {
                    return $this->jsonFailure('操作过于频繁，请稍后再试');
                }
                $this->redis->incr($redis_key);
                $this->redis->expire($redis_key, $redis_ttl);
            } else {
                $this->redis->setex($redis_key, 3600, 1);
            }

            $subscribe = new Subscribe();
            $subscribe->setEmail($email);
            $subscribe->setIp($request->getClientIp());
            $subscribe->setCreatedAt(new \DateTime());
            $this->getDoctrine()->getManager()->persist($subscribe);
            $this->getDoctrine()->getManager()->flush();
            return $this->jsonSuccess('订阅成功');
        } else {
            return $this->jsonFailure('请求错误');
        }
    }

    /**
     * 点赞
     * @param Request $request
     * @Route("/common/like/{id}", methods={"POST"}, name="common_like")
     * @ParamConverter("page", class="App\Entity\Page")
     * @param Request $request
     * @param Page $page
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     */
    public function like (Request $request, Page $page) {
        if ($request->isXmlHttpRequest()) {
            $ip = $request->getClientIp();
            $redis_key = $this->getParameter('app.name').':like:'.$ip.'.'.$request->get('id');
            if ($this->redis->exists($redis_key)) {
                return $this->jsonFailure('一小时内同一篇博文只能点赞一次');
            }
            $page->setPageLike($page->getPageLike() + 1);
            $this->getDoctrine()->getManager()->flush();
            $this->redis->setex($redis_key, 3600, 1);
            return $this->jsonSuccess();
        } else {
            return $this->jsonFailure('请求错误');
        }
    }

    /**
     * 图集
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function gallery () {
        $gallery = $this->getDoctrine()->getRepository(Gallery::class)->findBy([], ['sort' => 'ASC']);
        return $this->render('frontend/default/gallery.html.twig', [
            'gallery' => $gallery,
        ]);
    }

    /**
     * footer
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function footer () {
        $mine = $this->getDoctrine()->getRepository(Setting::class)->getCurrentSetting();
        $category = $this->getDoctrine()->getRepository(PageCategory::class)->findAll();
        return $this->render('frontend/public/footer.html.twig', [
            'mine'     => $mine,
            'category' => $category,
        ]);
    }
}